/**
 * Copyright (C) 2017 - 2020 https://github.com/joewee
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.bifrost.web.controller;

import com.bifrost.annotation.Authorization;
import com.bifrost.annotation.CurrentStore;
import com.bifrost.annotation.CurrentUser;
import com.bifrost.constant.CouponTypes;
import com.bifrost.constant.SendCouponType;
import com.bifrost.entity.Coupon;
import com.bifrost.entity.CouponDetail;
import com.bifrost.entity.Customer;
import com.bifrost.entity.MerchantStore;
import com.bifrost.exception.BonusPointsNotEnoughException;
import com.bifrost.exception.CancleConsumeException;
import com.bifrost.exception.ConsumeCouponException;
import com.bifrost.model.CouponModel;
import com.bifrost.model.CouponResponse;
import com.bifrost.common.model.ResultModel;
import com.bifrost.service.CouponService;
import com.bifrost.service.CustomerService;
import com.bifrost.service.StoreService;
import com.bifrost.util.TransformUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *优惠券相关接口
 *
 *@author joewee
 *@version 1.0.0
 *@Date 2017/11/19 16:54
 */
@RestController
@RequestMapping("/api/coupon")
@Api("优惠券相关功能接口")
public class CouponController {
    private static final Logger LOGGER = LoggerFactory.getLogger(CouponController.class);
    @Autowired
    CouponService couponService;
    @Autowired
    StoreService storeService;
    @Autowired
    CustomerService customerService;
    @Authorization
    @ApiOperation("获取用户未使用的优惠券")
    @GetMapping("/unused")
    public ResultModel getUnusedCoupons(@CurrentUser Long userId){
        Customer customer = customerService.findCustomer(userId);
        List<CouponDetail> detailList = couponService.getUnusedCoupons(customer);
        List<CouponModel> coupons = new ArrayList<>();
        List<Long> couponIds=new ArrayList<>();
        detailList.forEach(couponDetail->{
            Long couponId =couponDetail.getCoupon().getCouponId();
            if(couponIds.contains(couponId)){
                CouponModel model= coupons.get(couponIds.indexOf(couponId));
                model.setQuantity(model.getQuantity()+1);
            }else{
                coupons.add(TransformUtils.transformToCouponModel(couponDetail));
                couponIds.add(couponId);
            }
        });
        return ResultModel.ok("成功").put("coupons",coupons);
    }
    @Authorization
    @ApiOperation("获取用户已使用的优惠券")
    @GetMapping("/used")
    public ResultModel getUsedCoupons(@CurrentUser Long  userId){
        Customer customer = customerService.findCustomer(userId);
        List<CouponDetail> detailList = couponService.getUsedCoupons(customer);
        List<CouponModel> coupons = new ArrayList<>();
        detailList.forEach(couponDetail->{
            coupons.add(TransformUtils.transformToCouponModel(couponDetail));
        });
        return ResultModel.ok("成功").put("coupons",coupons);
    }
    @Authorization
    @ApiOperation("获取用户已使用的优惠券")
    @GetMapping("/expired")
    public ResultModel getExpiredCoupons(@CurrentUser Long userId){
        Customer customer = customerService.findCustomer(userId);
        List<CouponDetail> detailList = couponService.getExpiredCoupons(customer);
        List<CouponModel> coupons = new ArrayList<>();
        detailList.forEach(couponDetail->{
            coupons.add(TransformUtils.transformToCouponModel(couponDetail));
        });
        return ResultModel.ok("成功").put("coupons",coupons);
    }
    @Authorization
    @ApiOperation("领取优惠券")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "couponId", dataType = "Long", value = "优惠券ID", required = true)
    })
    @GetMapping("/get")
    public ResultModel getCoupon(@CurrentUser Long userId,@RequestParam Long couponId){
        Customer customer = customerService.findCustomer(userId);
        CouponResponse response = null;
        try {
            response = couponService.getCoupon( customer,couponId, SendCouponType.BASIC);
        } catch (BonusPointsNotEnoughException e) {
            return ResultModel.error(e.getErrorMsg());
        }
        if(response!=null&&response.isSuccess()){
            CouponModel couponModel = TransformUtils.transformToCouponModel(response.getCouponDetail());
            return ResultModel.ok("成功").put("coupon",couponModel);
        }else{
            return ResultModel.error(response.getFailureReason());
        }

    }
    @ApiOperation("获取优惠券列表")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "type", dataType = "String", value = "优惠券类型", required = true)
    })
    @GetMapping("/list")
    public ResultModel getCoupon(@RequestParam String type, @CurrentStore Long storeId){
        Assert.hasText(type,"优惠券类型不能为空");
        Assert.notNull(storeId,"门店信息未找到");
        MerchantStore store = storeService.getMerchantStore(storeId);
        List<Coupon> coupons = couponService.getCoupons(type,store);
        if(coupons==null){
            return ResultModel.ok();
        }
        List<CouponModel> couponModels =new ArrayList<>(coupons.size());
        coupons.forEach(coupon -> {
            couponModels.add(TransformUtils.transformToCouponModel(coupon));
        });
        return ResultModel.ok().put("coupons",couponModels);
    }
    @Authorization
    @ApiOperation("用兑换码兑换优惠券")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "code", dataType = "String", value = "兑换码", required = true)
    })
    @PostMapping("/redeem")
    public ResultModel redeemCoupon(@CurrentUser Long userId,@RequestParam String code){
        if(StringUtils.isEmpty(code)){
            return ResultModel.error("请输入兑换码");
        }
        Customer customer = customerService.findCustomer(userId);
        List<CouponResponse> responses = couponService.redeemCoupon( customer,code);
        if(CollectionUtils.isNotEmpty(responses)){
           List coupons = new ArrayList<>(responses.size());
           List<CouponResponse> unavalibleCoupons = new ArrayList<>(responses.size());
            responses.stream().filter(couponResponse -> {
                if(!couponResponse.isSuccess()){
                    if(LOGGER.isDebugEnabled()){
                        LOGGER.debug(String.format("优惠券%s领取不成功：%s",couponResponse.getCoupon().toString(),couponResponse.getFailureReason()));

                    }
                    unavalibleCoupons.add(couponResponse);
                }
                return couponResponse.isSuccess();
            }).forEach(couponResponse -> {
                CouponModel couponModel = TransformUtils.transformToCouponModel(couponResponse.getCouponDetail());
                coupons.add(couponModel);
            });
            if (CollectionUtils.isNotEmpty(coupons)) {
                return ResultModel.ok("兑换成功，请前往'我的优惠券'查看").put("coupons",coupons);
            }else{
                CouponResponse response = unavalibleCoupons.stream().findFirst().get();
                return ResultModel.error(response.getFailureReason());
            }
        }else{
            return ResultModel.error("您输入的兑换码不正确");
        }

    }
    /**
     *
     * 重百支付平台调用接口请勿修改----------------------start----------------------------------------
     * **/
    @ApiOperation("线下券生成消费码")
    @Authorization
    @GetMapping("/generate")
    public ResultModel generate(@CurrentUser Long userId,@RequestParam Long couponId){
        Customer customer = customerService.findCustomer(userId);
        CouponDetail detail = couponService.findCouponDetail(customer,couponId);
        if(detail==null){
            return ResultModel.error("不存在指定的优惠券");
        }else if(!CouponTypes.OFFLINE_COUPON.getType().equals(detail.getCouponTypeCode())){
            return ResultModel.error("该优惠券不能线下使用");
        }else{
            try {
                couponService.generateConsumeCode(detail);
            } catch (ConsumeCouponException e) {
                return ResultModel.error(e.getErrorMsg());
            }
            long expiredTime = detail.getGeneratedTime().getTime()+5*60*1000;
            return ResultModel.ok().put("consumeCode",detail.getConsumeCode())
                    .put("detail",detail.getCouponDescription())
                    .put("generatedTime",detail.getGeneratedTime())
                    .put("expiredTime",expiredTime);
        }
    }
    @ApiOperation("获取优惠券列表")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "outTradeNo", dataType = "String", value = "外部交易号", required = true),
            @ApiImplicitParam(paramType = "query", name = "couponCode", dataType = "String", value = "优惠券消费码", required = true),
            @ApiImplicitParam(paramType = "query", name = "totalFee", dataType = "int", value = "订单金额", required = true)
    })
    @GetMapping("/query")
    public ResultModel query(@RequestParam String outTradeNo,@RequestParam String couponCode,@RequestParam int totalFee,@RequestParam String store ){
        if (StringUtils.isBlank(store)) {
            return ResultModel.error("门店信息不能为空");
        }
       /*MerchantStore merchantStore = storeService.getMerchantStoreByExternalId(store);
        if(merchantStore==null){
            return ResultModel.error("门店信息不正确");
        }*/
        CouponDetail detail = couponService.queryByConsumeCode(couponCode);
        if(detail==null){
           return ResultModel.error("不存在指定消费码的优惠券");
       }/*else if(!merchantStore.equals(detail.getReleaseBy())){
            return ResultModel.error(String.format("优惠券不能在门店%s使用",store));
        }*/else if(!couponService.isAvailable(detail)){
           return ResultModel.error("优惠券不可用");
       }else if((detail.getGeneratedTime().getTime()+5*60*1000)<System.currentTimeMillis()){
           return ResultModel.error("消费码已过期");
       }else{
           Map data = new HashMap(2);
           data.put("ruleCode",detail.getRuleCode());
           data.put("couponFee",detail.getDiscountAmount().multiply(BigDecimal.valueOf(100)));
           return ResultModel.ok().put("data",data);
       }
    }
    @ApiOperation("核销优惠券")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "outTradeNo", dataType = "String", value = "外部交易号", required = true),
            @ApiImplicitParam(paramType = "query", name = "couponCode", dataType = "String", value = "优惠券消费码", required = true),
            @ApiImplicitParam(paramType = "query", name = "totalFee", dataType = "int", value = "订单金额", required = true)
    })
    @PostMapping("/consume")
    public ResultModel consume(@RequestParam String outTradeNo,@RequestParam String couponCode,@RequestParam int totalFee, @RequestParam String store ){
        if (StringUtils.isBlank(store)) {
            return ResultModel.error("门店信息不能为空");
        }
       /* MerchantStore merchantStore = storeService.getMerchantStoreByExternalId(store);
        if(merchantStore==null){
            return ResultModel.error("门店信息不正确");
        }*/

        CouponDetail detail = couponService.findByConsumeCode(couponCode);
        if(detail==null){
            return ResultModel.error("优惠券消费码错误");
        }else{
            try {
               Long tradeNo = couponService.consumeCoupon(outTradeNo,couponCode,totalFee);
                Map data = new HashMap(2);
                data.put("transactionId",tradeNo);
                data.put("couponFee",detail.getDiscountAmount().multiply(BigDecimal.valueOf(100)));
                return ResultModel.ok().put("data",data);
            } catch (ConsumeCouponException e) {
                return ResultModel.error(e.getErrorMsg());
            }

        }
    }
    @ApiOperation("优惠券冲正")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "outTradeNo", dataType = "String", value = "外部交易号", required = true)
    })
    @PostMapping("/cancel")
    public ResultModel cancel(@RequestParam String outTradeNo){
        if (StringUtils.isBlank(outTradeNo)) {
            return ResultModel.error("outTradeNo不能为空");
        }
        try {
            couponService.cancleConsumeCoupon(outTradeNo);
            return ResultModel.ok();
        } catch (CancleConsumeException e) {
            return ResultModel.error(e.getErrorMsg());
        }
    }
    @ApiOperation("优惠券退款")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "outTradeNo", dataType = "String", value = "外部交易号", required = true)
    })
    @PostMapping("/refund")
    public ResultModel refund(@RequestParam String outTradeNo,@RequestParam Long transactionId){
        if (StringUtils.isBlank(outTradeNo)) {
            return ResultModel.error("outTradeNo不能为空");
        }
        if (transactionId==null) {
            return ResultModel.error("系统交易号transactionId不能为空");
        }
        try {
           Long id = couponService.refundCoupon(outTradeNo,transactionId);
            return ResultModel.ok().put("transactionId",id);
        } catch (CancleConsumeException e) {
            return ResultModel.error(e.getErrorMsg());
        }
    }
    @ApiOperation("查询优惠券退款")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "outTradeNo", dataType = "String", value = "外部交易号", required = true)
    })
    @PostMapping("/refundQuery")
    public ResultModel refundQuery(@RequestParam String outTradeNo,@RequestParam Long transactionId){
        if (StringUtils.isBlank(outTradeNo)) {
            return ResultModel.error("outTradeNo不能为空");
        }
        if (transactionId==null) {
            return ResultModel.error("系统交易号transactionId不能为空");
        }
        try {
            if(couponService.refundQuery(outTradeNo,transactionId)){
                return ResultModel.ok();
            }else{
                return ResultModel.error("退回优惠券失败");
            }
        } catch (CancleConsumeException e) {
            return ResultModel.error(e.getErrorMsg());
        }
    }
    /**
     *
     * 重百支付平台调用请勿修改------------------end----------------------------------------
     * **/
}

